package org.gitman.agent.platform;

import javax.swing.JOptionPane;

import org.gitman.agent.gui.MainFrame;
import org.gitman.agent.gui.SimulationPanel;

import com.mxgraph.model.mxICell;
import com.mxgraph.view.mxGraph;

public class Simulation {

	private AgentManager agentManager;
	private mxGraph graph;
	private int maxNumberOfIterations = 100; 
	private int dely = 300;
	private PlatformManager platformManager;
	private int step = 0;
	private boolean initialized = false;
	private int iteration = 0;
	private GraphSimmulationViewer viewer;
	private SimulationPanel simulationPanel;
	private MainFrame mainFrame;
	private SimmulationThread simmulationThread;
	

	public Simulation(PlatformManager platformManager){
		this.platformManager = platformManager;
		agentManager = new AgentManager(platformManager);
		viewer = new GraphSimmulationViewer(this);
		mainFrame = platformManager.getMainFrame();
	}
	
	public AgentManager getAgentManager() {
		return agentManager;
	}
	
	public void init(){
		graph = platformManager.getGraphEditor().getGraph();
		step = 0;
		agentManager.initializeAgentQueue();
		viewer.init(graph);
		simulationPanel = platformManager.getMainFrame().getSimulationPanel();
		initialized = true;
		
	}
	
	public void setMaxNumberOfIterations(int maxNumberOfIterations){
		this.maxNumberOfIterations = maxNumberOfIterations;
	}
	
	public void doStep() {
		if(!initialized){
			init();
		}		
		Agent agent = agentManager.nextAgent();
		if(agent != null){
			step++;
			simulationPanel.setStep(step);
			int ai = agent.getIteration();
			if(ai == iteration){
				iteration++;
				simulationPanel.setIteration(iteration);
			}
			if(iteration >= maxNumberOfIterations){
				JOptionPane.showMessageDialog(platformManager.getMainFrame(), 
						"Simmulation has reached max number of iterations: " + maxNumberOfIterations, 
						"Simmulation stopped", JOptionPane.INFORMATION_MESSAGE);
			}else{
				agent.setIteration(iteration);	
				mxICell move = agent.doStep(graph, agentManager);
				if(!move.equals(agent.getCurrentPoint())){
					if(!move(agent, move)){
						appendLog("[WARNING]: can't move where it want", agent);
					}else{
						appendLog("moved", agent);
					}
				}else{
					appendLog("No moves", agent);
				}
				if(agent.reachTarget()){
					agent.setState(AgentState.done);
					viewer.agentFinished(agent);
					appendLog("I am in place! after: " + agent.getIteration() + " iterations", agent);
				}else{
					if(!agent.canReachTarget(graph)){
						agent.setState(AgentState.locked);
						appendLog("I am locked", agent);
					}
					agentManager.addAgent2Queue(agent);					
				}
				simulationPanel.updateAgentsTab();
			}
		}else{
			JOptionPane.showMessageDialog(platformManager.getMainFrame(), "All agents are in place!!", "Simmulation Complete", JOptionPane.INFORMATION_MESSAGE);
		}
	}
	
	public void play(){
		if(!initialized){
			init();
			simmulationThread = new SimmulationThread();
			simmulationThread.start();
		}else{
			if(iteration < maxNumberOfIterations){
				if(simmulationThread != null){
					simmulationThread.resume();
				}else{
					simmulationThread = new SimmulationThread();
					simmulationThread.start();
				}				
			}
		}
	}
	
	private boolean move(Agent agent, mxICell move) {
		boolean success = true;
		mxICell before = agent.getCurrentPoint();
		if(AgentUtils.getAllChilds(before, graph, true).contains(move)){
			agent.setCurrentPoint(move);
			viewer.moveAgent(agent, before, move);
		}else{
			success = false;
		}
		return success;
	}

	public void appendLog(String message, Agent agent) {
		String text = agent.toString() + ": " +message;
		mainFrame.appendLog(text);
		System.out.println(text);
	}
	
	public boolean isInitialized(){
		return initialized;
	}
	
	public void setDely(int dely) {
		this.dely = dely;
	}
	
	public void pause(){
		simmulationThread.suspend();
	}
	
	public void restart(){
		//TODO restart simulation
	}
	
	class SimmulationThread extends Thread{
		
		public void run(){
			while(agentManager.getAllAgentsInQueue().size() != 0 && iteration < maxNumberOfIterations){
				doStep();
				try {
					Thread.sleep(dely);
				} catch (InterruptedException e) {
					e.printStackTrace();
			}
			}
		}
		}

	
}
